#include <Arduino.h>
#include <WiFiManager.h>
#include "server.h"

#define LEDC_CHANNEL_0 0     //pwm频道0
#define LEDC_TIMER_8_BIT 8   //pwm分辨率0-255
#define LEDC_BASE_FREQ 5000  //pwm基础频率

#define PIN_PWM_LIGHT 0     //pwm控制灯亮度
#define PIN_ADC_LIGHT 1     //光敏电阻电压读取
#define PIN_LD2410_CHK 3    //人体感应模块
#define PIN_POWER_CHECK 10  //供电方式检测引脚
#define PIN_PWM_ACTION1 4   //PWM鞠躬引脚

#define HEARTBEAT_MS 500  //loop心跳时间

#define BREATHE_INTERVAL_MS 3000  //led呼吸间隔时间
#define FADE_SLOW_INTERVAL_MS 30  //慢速LED灯亮度变化
#define FADE_FAST_INTERVAL_MS 5   //快速LED灯亮度变化

#define ADC_THERSHOLD_IDLE 250    //空闲时光敏电阻阈值，正常室内800左右，暗光环境为250左右
#define ADC_THERSHOLD_ACTIVE 650  //活跃时光敏电阻阈值
#define ADC_THERSHOLD_DIFF 40     //光敏电阻差异阈值 小于这个值不变化

#define ACTION_INTERVAL_MS 14400000  //鞠躬间隔时间 4*3600*1000 4hrs
#define ACTION_PRE_DELAY_MS 500      //鞠躬前准备时间
#define ACTION_HOLD_MS 2500          //控制鞠躬保持时间

#define SEDENTARY_THERSHOLD_MS 5400000  //久坐提醒间隔 90*60*1000 1.5hrs

int pwm_current = 0;  //LED pwm输出 0-255

int sys_state = 0;  //模式

uint32_t ts_last_breathe = 0;                         //led上一次呼吸时间
uint32_t ts_last_action = ACTION_INTERVAL_MS + 1000;  //上一次鞠躬时间
uint32_t ts_last_sedentary = 0;                       //上一次久坐时间

//led闪烁变化
int lum_steps[31] = { 0, 3, 8, 15, 24, 35, 48, 63, 80, 99, 120, 143, 168, 195, 224, 255, 224, 195, 168, 143, 120, 99, 80, 63, 48, 35, 24, 15, 8, 3, 0 };

/**
 * ----------------------
 * functions
 * ----------------------
 */

/**
    @brief  读取光敏电阻产生的电压变化，转换为0-1023的数值，3次求平均
*/
int adc_current(void) {
  int adc_values_total = analogRead(PIN_ADC_LIGHT);
  adc_values_total += analogRead(PIN_ADC_LIGHT);
  adc_values_total += analogRead(PIN_ADC_LIGHT);
  adc_values_total /= 3;
  adc_values_total = map(adc_values_total, 0, 4095, 0, 1023);
  return adc_values_total;
}

/**
    @brief  前者adc_target是目标adc值（并不控制亮度，最大亮度即PWM为255的亮度），后者控制变化速度
*/
void fade_to(int adc_target, int fade_interval) {
  // choose direction
  int adc_diff = adc_current() - adc_target;
  if (abs(adc_diff) < ADC_THERSHOLD_DIFF) {
    return;
  }
  if (adc_diff < 0) {
    // step up变亮
    while (adc_current() < adc_target) {
      if (pwm_current < 255) {
        pwm_current++;
        ledcWrite(LEDC_CHANNEL_0, pwm_current);
        delay(fade_interval);
      } else {
        return;
      }
    }
  } else {
    // step down变暗
    while (adc_current() >= adc_target) {
      if (pwm_current > 0) {
        pwm_current--;
        ledcWrite(LEDC_CHANNEL_0, pwm_current);
        delay(fade_interval);
      } else {
        return;
      }
    }
  }
}

//无人 呼吸效果
void breathe(void) {
  fade_to(ADC_THERSHOLD_IDLE, FADE_SLOW_INTERVAL_MS);
  fade_to(0, FADE_SLOW_INTERVAL_MS);
}
//鞠躬
void bow(void) {
}
//久坐 闪烁效果
void flash(void) {
  for (int i = 0; i < 31; i++) {
    analogWrite(PIN_PWM_LIGHT, lum_steps[i]);
    delay(10);
  }
}
//久坐提醒
void alert(void) {
  fade_to(0, FADE_FAST_INTERVAL_MS);
  delay(1000);
  flash();
  delay(700);
  for (size_t i = 0; i < 4; i++) {
    flash();
    delay(100);
  }
  delay(1000);
  pwm_current = 0;
}
/**
 * ----------------------
 * logics
 * ----------------------
 */
/**
    @brief 0 空闲状态 人体感应 无人则进行呼吸效果 有人则跳转到下一个阶段
*/
void state_idle(void) {
  if (digitalRead(PIN_LD2410_CHK)) {
    // change to middle stage state
    sys_state = 10;
  } else {
    // breathe
    if ((unsigned long)(millis() - ts_last_breathe) > BREATHE_INTERVAL_MS) {
      {
        breathe();
        ts_last_breathe = millis();
      }
    }
  }
}
//准备有人在的情况
void state_pre_active(void)  // 10
{
  // light up
  fade_to(ADC_THERSHOLD_ACTIVE, FADE_FAST_INTERVAL_MS);

  // bow?
  if ((unsigned long)(millis() - ts_last_action) > ACTION_INTERVAL_MS) {
    // action
    delay(ACTION_PRE_DELAY_MS);
    bow();
    ts_last_action = millis();
  }

  // start sendentary counter
  ts_last_sedentary = millis();

  // change to present state
  sys_state = 20;
}
//有人的情况
void state_active(void)  // 20
{
  if (digitalRead(PIN_LD2410_CHK)) {
    fade_to(ADC_THERSHOLD_ACTIVE, FADE_FAST_INTERVAL_MS);

    // sedentary?
    if ((unsigned long)(millis() - ts_last_sedentary) > SEDENTARY_THERSHOLD_MS) {
      alert();
      ts_last_sedentary = millis();
      fade_to(ADC_THERSHOLD_ACTIVE, FADE_FAST_INTERVAL_MS);  //恢复正常亮度
    }
  } else {
    sys_state = 30;
  }
}

//无人
void state_pre_idle(void)  // 30
{
  fade_to(ADC_THERSHOLD_IDLE, FADE_SLOW_INTERVAL_MS);
  sys_state = 0;
}

void setup() {

  pinMode(PIN_PWM_LIGHT, OUTPUT);   //pwm控制灯亮度
  pinMode(PIN_ADC_LIGHT, INPUT);    //光敏电阻电压读取
  pinMode(PIN_LD2410_CHK, INPUT);   //人体感应模块
  pinMode(PIN_POWER_CHECK, INPUT);  //判断供电方式引脚输入模式

  if (digitalRead(PIN_POWER_CHECK)) {  // 判断为无线或有线供电，若为有线供电，打开wifi功能
    WiFiManager wifiManager;
    wifiManager.autoConnect("aMagicLight2");
    Server_Init();
  }

  ledcSetup(LEDC_CHANNEL_0, LEDC_BASE_FREQ, LEDC_TIMER_8_BIT);
  ledcAttachPin(PIN_PWM_LIGHT, LEDC_CHANNEL_0);
}

void loop() {
  switch (sys_state) {
    case 0:
      state_idle();
      break;

    case 10:
      state_pre_active();
      break;

    case 20:
      state_active();
      break;

    case 30:
      state_pre_idle();
      break;

    default:
      // error
      sys_state = 0;
      break;
  }
  delay(HEARTBEAT_MS);
}
